/**
 * 常用工具方法
 */
import { Regexp_Utils } from "./validate";

// 手机号码掩码处理
export const coverPhone = (phone, option = { prefix: '+86 ', needPrefix: false }) => {
    if (Regexp_Utils.phone.test(phone)) {
        const coveredPhone = phone.slice(0, 3) + '*'.repeat(4) + phone.slice(-4);
        return option.needPrefix ? option.prefix + coveredPhone : coveredPhone;
    }
    return `不合法手机号`;
}


/**
 * 获取随机数，如果是浏览器环境可以使用 window.Crypto.getRandomValues(), 参考 https://developer.mozilla.org/zh-CN/docs/Web/API/Crypto/getRandomValues
 * @param len 随机数的位数
 * @returns 获取随机数
 */
export const getRandomNumber = (len = 5) => Math.floor(Math.random() * Math.pow(10, len));


/**
 * 根据时间戳+随机数获取随机字符串，也可以考虑使用Symbol
 * @param len 随机数长度
 * @param seprator 分割符号
 * @returns 随机字符串
 */
export const getRandomDateString = (len = 3, seprator = '_') => `${Date.now()}${seprator}${getRandomNumber(len)}`;


/**
 * 页面跳转到登录页
 * @param loginSuccessPath 登录成功后的跳转路径
 * @returns Promise
 * **/
export function toLoginPage(loginSuccessPath) {
    const routes = getCurrentPages(), currentRoute = routes[routes.length - 1];    
    let from = '/';
    if (loginSuccessPath) {
        from = encodeURIComponent(loginSuccessPath)
    } else if (currentRoute?.$vm?.$page?.options?.from) {
        from = encodeURIComponent(currentRoute?.$vm?.$page?.options?.from);
    } else {
        from = encodeURIComponent((currentRoute?.$vm?.$page?.fullPath ?? '/'));
    }
	
	
	// 如果当前页面为登录页，则直接返回
	if (from.indexOf('/login/index') > -1) {
	    return;
	}

    return uni.navigateTo({
		url: `/pages/login/index?from=${from}`,
	});
}

/**
 * 节流函数，用于限制某个函数在指定时间内的调用频率。
 * 
 * @param func - 需要被节流的函数。
 * @param wait - 节流的时间间隔，单位为毫秒，默认为 300 毫秒。
 * @returns 返回一个新的函数，该函数在指定时间内只会执行一次。
 */
export function throttleFunction(func, wait) {
    let waitTime = wait || 300;
    let timer = undefined;
    return function (...args) {
        if (!timer) {
            func.apply(this, args); // 先执行, 写法1
            timer = setTimeout(() => {
                // func.apply(this, args); // 后执行, 写法2
                clearTimeout(timer);
                timer = undefined;
            }, waitTime);
        }
    };
}

/**
 * 防抖函数，用于限制某个函数在指定时间内的调用频率。
 * 
 * @param func - 需要防抖的函数。
 * @param wait - 防抖的时间间隔，单位为毫秒，默认为 300 毫秒。
 * @returns 返回一个新的防抖函数。
 * 
 * 使用示例：
 * const debouncedFunction = debounceFunction(() => {
 *     console.log('Function executed!');
 * }, 500);
 */
export function debounceFunction(func, wait) {
    let waitTime = wait || 300;
    let timer= undefined;
    return function (...args) {
        clearTimeout(timer);
        timer = undefined;
        timer = setTimeout(() => {
            func.apply(this, args);
            clearTimeout(timer);
            timer = undefined;
        }, waitTime);
    };
}


/**
 * 深度复制对象
 * @param {*} source 深度拷贝的目标对象
 * @returns 完成拷贝的对象
 */
export const deepCopy = (source, cache = new Map()) => {
    if (!source || !(source instanceof Object) || source instanceof Function) {
        return source;
    }

    // 防止循环引用
    if (cache.has(source)) {
        return cache.get(source);
    }


    if (Array.isArray(source)) {
        const result = source.map(item => deepCopy(item, cache));
        cache.set(source, result);
        return result;
    }

    if (Object.prototype.toString.call(source) == '[object Date]') {
        return new Date(source.getTime());
    }

    let target = Object.create(Object.getPrototypeOf(source)); // 复制原型对象
    for (let key of Object.keys(source)) { // 复制本身
        target[key] = deepCopy(source[key], cache);
    }
    cache.set(source, target);

    return target;
}

/**
 * 深度合并两个对象，并返回目标对象; Object.assign 只合并一层
 * @param {Object} target 需要重新赋值的对象
 * @param {(Object|Array)} source 需要被合并的对象
 * @returns {Object} 合并后的对象
 */
export function mergeObject(target, source) {
  if (typeof target !== 'object'||target===null) {
	  target = {}
  }
  if (Array.isArray(source)) {
	  return source.slice()
  }
  Object.keys(source).forEach(property => {
	  const sourcePropertyVal = source[property]
	  if (typeof sourcePropertyVal === 'object'&&sourcePropertyVal!==null) {
		  target[property] = mergeObject(target[property], sourcePropertyVal)
	  } else {
		  target[property] = sourcePropertyVal
	  }
  })
  return target
}


/**
 * 缓存工具类，提供对localStorage本地存储的封装操作
 * @export
 * @class CacheUtils
 */
export const CacheUtils = {
    set(key, value, expireDate) {
        uni.setStorage({
            key: '_' + key,
            data: JSON.stringify(value),
        });
        if (expireDate) {
            uni.setStorage({
                key: '_' + key + '_expireDate',
                data: String(expireDate.getTime()),
            });
        }
    },
    get(key) {
        const timestamp = uni.getStorageSync('_' + key + '_expireDate');
        if (timestamp) {
            const expireDate = new Date(Number(timestamp));
            if (expireDate.getTime() < new Date().getTime()) {
                CacheUtils.remove(key);
                return null;
            }
        }
        const content = uni.getStorageSync('_' + key)||'null';
        return JSON.parse(content);
    },

    remove(key) {
        uni.removeStorageSync('_' + key);
        uni.removeStorageSync('_' + key + '_expireDate');
    }
}



// Tab页面列表的url
const tabPages = [
    '/',
    '/pages/index/index',
    '/pages/message/index',
    '/pages/user/index',
]

/**
 * 导航到uniapp指定页面。
 * 如果目标页面已在标签页中，则切换到该标签页；否则，打开新页面。
 * @param url - 目标页面的路径。
 */
export const navigateToUniPage = (url) => {
    const matchIndex = tabPages.findIndex((el) => el == url.split('?')[0]);
    if (matchIndex!== -1) {
        if(matchIndex == 0) {
            return uni.switchTab({ url: tabPages[1], });
        }
        return uni.switchTab({ url, });
    }

    return uni.navigateTo({ url, })
}

/**
 * 返回上一页面或多级页面
 * @param {*} delta 返回的页面数，如果 delta 大于现有页面数，则返回到首页。
 * @returns 
 */
export const navigateBack = (delta=1)=>{
    return uni.navigateBack({
        delta: delta,
    });
}

/**
 * 日期格式化，甚牛而逼之
 * @param date - 要格式化的日期对象。
 * @param format - 日期样式。
 * @returns 格式化后的日期字符串。
 */
export const formatDate = (date, format = 'YYYY-MM-DD HH:mm:ss') => {
    // padStart() 方法用另一个字符串填充当前字符串（如果需要会重复填充），直到达到给定的长度。填充是从当前字符串的开头开始的; 类似有padEnd()方法
    const pad = (num) => String(num).padStart(2, '0'); 

    return format
        .replace(/YYYY/g, String(date.getFullYear()))
        .replace(/MM/g, pad(date.getMonth() + 1))
        .replace(/DD/g, pad(date.getDate()))
        .replace(/HH/g, pad(date.getHours()))
        .replace(/mm/g, pad(date.getMinutes()))
        .replace(/ss/g, pad(date.getSeconds()))
        .trim();
}

/**
 * PHP 秒级时间戳格式化
**/
export const translatePhpTimeToData = (seconds, format=false)=>{
	if(!format){
		return new Date(seconds*1000);
	}
	return formatDate(new Date(seconds*1000));
}

/**
 * 将字符串转换为布尔值, 一般用于env配置文件的转换
 * @param str 需要转换的字符串,只能是 'true' 或 'false'
 * @returns 如果输入 'true' 返回 true,否则返回 false
 */
export function StringToBoolean(str) {
    if (str === 'true') {
        return true;
    } else if (str === 'false') {
        return false;
    }

    return false;
}

/**
 * url+参数编码，例如 encodeUrlwithArgs('pages/home/index', 'a',1, 'b, 2) => 'pages/home/index?a=1&b=2'
 * @param {*} url 主机url
 * @param  {...any} args 多个传入的参数
 */
export const encodeUrlwithArgs = (url, ...args)=>{
    let resultUrl = String(url);
    for(let i=0;i<args.length;i+=2){
        resultUrl = resultUrl.includes('?') ? resultUrl+`&${args[i]}=${args[i+1]}`: resultUrl+`?${args[i]}=${args[i+1]}`;
    }
    return resultUrl;
}

/**
 * Url+对象后进行编码（不支持对象嵌套结构）
 * @param {*} url 主机url
 * @param {*} obj 编码的对象
 * @returns 编码后的url
 */
export const encodeUrlWithObj = (url,obj={})=>{
    let arr = [];
    for(let [key, val ] of Object.entries(obj)){
        arr.push(key);
        arr.push(val);
    }
    return encodeUrlwithArgs(url, ...arr);
}

/**
 * 退出登录
 * t -- 多语言翻译
**/
export const toLogout = (t)=>{
	uni.showModal({
		title: t('common.confirm_title'),
		content: t('common.logoutComfirm'),
		confirmText: t('common.confirm'),
		cancelText: t('common.cancel'),
		success: function (res) {
			if (res.confirm) {
				CacheUtils.remove('userid');
				CacheUtils.remove('userInfo');
				return toLoginPage('/')
			} 
		}
	});
}

// 获取今日 某个时间的时间戳(协调世界时)
export const getCurrentDateOfMS = (hour, minutes, seconds=0)=>{
    const date = new Date();
    date.setHours(hour);
    date.setMinutes(minutes);
    date.setSeconds(seconds);
    return date.getTime();
}
